﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using NUnit.Framework;
using Legend.Fakes.Api;
using NUnit.Framework.Constraints;
using System.Linq.Expressions;
using System.IO;

namespace Legend.Fakes.Tests.Api
{
    [TestFixture]
    public class HelpersTests
    {
        [Test]
        public void GetDescription_should_throw_when_call_is_null()
        {
            Assert.Throws<ArgumentNullException>(() =>
                Helpers.GetDescription((IWriteableFakeObjectCall)null));
        }

        [Test]
        public void GetDescription_should_render_method_name_and_empty_arguments_list_when_call_has_no_arguments()
        {
            var call = new FakeCall
            {
                Method = typeof(object).GetMethod("GetType")
            };

            Assert.That(call.GetDescription(), Is.EqualTo("System.Object.GetType()"));
        }

        [Test]
        public void GetDescription_should_render_method_name_and_all_arguments_when_call_has_arguments()
        {
            var call = new FakeCall
            {
                Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                Arguments = new ArgumentList(new object[] { "abc", 123 })
            };

            Assert.That(call.GetDescription(), Is.EqualTo("Legend.Fakes.Tests.IFoo.Bar([System.Object] abc, [System.Object] 123)"));
        }

        [Test]
        public void GetDescription_should_render_NULL_when_argument_is_null()
        {
            var call = new FakeCall
            {
                Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                Arguments = new ArgumentList(new object[] { null, 123 })
            };

            Assert.That(call.GetDescription(), Is.EqualTo("Legend.Fakes.Tests.IFoo.Bar([System.Object] <NULL>, [System.Object] 123)"));
        }

        [Test]
        public void WriteCalls_should_throw_when_writer_is_null()
        {
            Assert.Throws<ArgumentNullException>(() =>
                Helpers.WriteCalls(GetStubCalls(), (TextWriter)null));
        }

        [Test]
        public void WriteCalls_should_throw_when_calls_is_null()
        {
            Assert.Throws<ArgumentNullException>(() =>
                Helpers.WriteCalls((IEnumerable<IFakeObjectCall>)null, new StringWriter()));
        }

        [Test]
        public void WriteCalls_should_write_all_calls_to_writer()
        {
            var calls = new List<IFakeObjectCall> 
            {
                new FakeCall
                {
                    Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                    Arguments = new ArgumentList(new object[] { "abc", 123 })
                },
                new FakeCall
                {
                    Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                    Arguments = new ArgumentList(new object[] { "def", 456 })
                }
            };

            var writer = new StringWriter();

            calls.WriteCalls(writer);

            Assert.That(writer.GetStringBuilder().ToString(), Is.EqualTo(
                @"Legend.Fakes.Tests.IFoo.Bar([System.Object] abc, [System.Object] 123)
Legend.Fakes.Tests.IFoo.Bar([System.Object] def, [System.Object] 456)
"));
        }

        private IEnumerable<IFakeObjectCall> GetStubCalls()
        {
            return new List<IFakeObjectCall> 
            {
                new FakeCall
                {
                    Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                    Arguments = new ArgumentList(new object[] { "abc", 123 })
                },
                new FakeCall
                {
                    Method = typeof(IFoo).GetMethod("Bar", new[] { typeof(object), typeof(object) }),
                    Arguments = new ArgumentList(new object[] { "def", 456 })
                }
            };
        }
    }
}
